<?php


class Verify_code_model extends Base_model {

    /**
     * 有效时间(秒), 默认为: 1800秒(30分钟)
     */
    const VALIDATE_TIME_SECOND = 1800;


    /**
     * 允许验证的最大次数
     */
    const MAX_CHECK_NUM = 3;


	/**
	 * 表名
	 * 
	 * @param string 
	 */
    public $_table_name = "verify_code";

	/**
	 * 错误信息
	 * 
	 * @param string 
	 */
    public $_error_info = "验证码不正确！";


    /**
     * 32位会话特征码
     * @var string 
     */
    public $token;


    /**
     * 验证码的值
     * @var string 
     */
    public $code_value;


    /**
     * 创建时间
     * @var int 
     */
    public $create_time;


	/**
     * 已验证次数
     * @var int 
     */
    public $check_num;


    /**
     * 验证码值数组
     * @var array 
     */
    public $_code_arr;


    /**
     * 插入数据前验证
     * 
     * @return boolean 
     */
    protected function prepare_insert() {

        if(empty($this->token)) {
            return false;
        }

        if(empty($this->code_value)) {
            $this->code_value = '';
        }

        if(empty($this->check_num)) {
            $this->check_num = 0;
        }

        return true;
    }

    
    /**
     * 搜索
     * 
     * @return boolean true | false
     */
    public function search() {
        $sql = "SELECT ";

        if(!empty($this->_selected_fields))
		{
			if (is_array($this->_selected_fields))
			{
				$sql .= implode(", ", $this->_selected_fields);
			}
			else
			{
				$sql .= $this->_selected_fields;
			}
        }
		elseif (!empty($this->_is_search_counter))
		{
            $sql .= " COUNT(vvc.id) AS rows_total ";
        }
		else
		{
            $sql .= " vvc.* ";
        }

        $sql .= " FROM {$this->_table_name} AS vvc ";

        $statement = "";
        $where = array();

        if (!empty($this->id)) {
            $statement .= " AND vvc.id = ? ";
            $where[] = $this->id;
        }

        if (!empty($this->code_value)) {
            $statement .= " AND vvc.code_value = ? ";
            $where[] = $this->code_value;
        }

		//处理条件
        if($statement) {
            $sql .= " WHERE " . substr($statement, 4);
        }

        if (!empty($this->_group_by)) {
            $sql .= " GROUP BY {$this->_group_by} ";
        }

        if (!empty($this->_is_search_counter)) {
            $sql .= " LIMIT 1";
        } else {
            if (!empty($this->_order_by)) {
                $sql .= " ORDER BY {$this->_order_by} ";
            }

			//是否分页
            if ($this->is_paging()) {

				$page_from = ($this->_page_index - 1) * $this->_page_count;

                $sql .= " LIMIT {$page_from}, {$this->_page_count}";
            }
        }

        $result = $this->db->query($sql, $where);

        if(empty($this->_is_search_counter))
		{
			$this->_search_results = array();

            if ($result->num_rows() > 0) {
                $this->_search_results = $result->result();
            }
        }
		else
		{
            if ($result->num_rows() > 0) {
                $row = $result->row();

                if (!empty($row->rows_total)) {
                    $this->_search_num_rows = $row->rows_total;
                }
            }
        }

        $result->free_result();

        return true;
    }


    /**
     * 检查验证码是否正确.
     * 
     * @param int $id
     * @param string $token
     * @param string $code_value
     * @return boolean 
     */
    public function check_verify_code($id, $token, $code_value) 
    {
        if(empty($id) || empty($token) || empty($code_value)){
			return false;
		}

		if(!$this->retrieve($id)){
			return false;
		}

		//会话特征码不正确时直接返回false
		if($this->token != $token){
			return false;
		}

		//超过验证次数删除记录(ajax表单验证有效)
		if($this->check_num >= self::MAX_CHECK_NUM){

			$this->_error_info = self::MAX_CHECK_NUM . " 次验证机会已用完！ 请" . (self::VALIDATE_TIME_SECOND/60) . "分钟后再试";
			return false;
		}

		//验证码过期
		if((time() - $this->create_time) > self::VALIDATE_TIME_SECOND){

			$this->_error_info = "验证码超时！";
			return false;
		}

		//验证成功返回true, 清除code_value值, 防止机器人重复使用当前验证码
		if($this->code_value == strtolower($code_value)){
			
			$this->code_value = '';
			$this->update();

			return true;
		}

		//验证码错误，增加验证次数
        $this->check_num += 1;
        $this->update();

		return false;
    }


    /**
     * 生成一个新验证码
     * 
     * @return boolean 
     */
    public function create_verify_code() 
    {
		//自动删除过期的验证码记录
		$this->auto_delete_expired();

		$this->token = md5(uniqid(mt_rand())); //生成唯一特征码
		$this->create_time = time();

		return $this->insert();
    }


    /**
     * 删除验证码
     * 
     * @param int $id
     * @return boolean 
     */
    public function delete_verify_code($id = 0) 
    {
        if(empty($id)){
			return false;
		}

		$sql = "DELETE FROM {$this->_table_name} WHERE id = ?";

		$this->db->query($sql, array($id));

		return true;
    }


    /**
     * 更新验证码
     * 
     * @param int $id
     * @param string $token
     * @return boolean 
     */
    public function refresh_verify_code($id, $token) 
    {
        if(empty($id) || empty($token)){
			return false;
		}

		if(!$this->retrieve($id)){
			return false;
		}

		if($this->token != $token){
			return false; //会话特征码不正确时直接返回false
		}

        $this->_code_arr = $this->create_rand_number(); //生成4位随机数字验证码数组
        $this->code_value = implode('', $this->_code_arr); //验证码字符串

		return $this->update();
    }


    /**
     * 保存验证码(用于输入框验证码, PC端使用)
     * 
     * @param int $id
     * @param string $token
     * @param string $code
     * @return boolean 
     */
    public function save_verify_code($id, $token, $code) 
    {
        if(empty($id) || empty($token) || empty($code)){
			return false;
		}

		if(!$this->retrieve($id)){
			return false;
		}

		if($this->token != $token){
			return false; //会话特征码不正确时直接返回false
		}

        $this->code_value = strtolower($code); //验证码字符串

		return $this->update();
    }



    /**
     * 从1-9随机生成四个不重复的数字的数组
     * 
     * @param int $begin
     * @param int $end
     * @param int $limit
     * @return array
     */
	private function create_rand_number($begin = 1, $end = 9, $limit = 4)
	{
		$rand_array = range($begin, $end);

		shuffle($rand_array); //将数组随机排列

		return array_slice($rand_array, 0, $limit); //截取前$limit个的数组
	}


    /**
     * 自动删除记录(达到自动维护的目的)
     * 
   * @return boolean
     */
	private function auto_delete_expired()
	{
		if((mt_rand() % 100) < 5)
		{
			$sql = "DELETE FROM {$this->_table_name} WHERE create_time < " . (time() - self::VALIDATE_TIME_SECOND - 1800);

	    	$this->db->query($sql);
		}
	}

}